package role

import (
	"AccessAdmin/internal/dao"
	"AccessAdmin/internal/model"
	"AccessAdmin/internal/model/entity"
	"AccessAdmin/internal/service"
	"AccessAdmin/utility/utils"
	"context"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

type sRole struct {
}

func init() {
	service.RegisterRole(New())
}

func New() *sRole {
	return &sRole{}
}

// 获取角色列表
func (s *sRole) GetList(ctx context.Context, in model.RoleGetListInput) (out *model.RoleGetListOutput, err error) {
	out = &model.RoleGetListOutput{
		Page: in.Page,
		Size: in.Size,
	}
	m := dao.Role.Ctx(ctx)
	if in.Name != "" {
		m = m.WhereLike(dao.Role.Columns().Name, in.Name)
	}
	if in.Identify != "" {
		m = m.WhereLike(dao.Role.Columns().Identify, in.Identify)
	}
	if in.Status > 0 {
		m = m.Where(dao.Role.Columns().Status, in.Status-1)
	}
	out.Total, err = m.Count()
	if err != nil {
		return out, err
	}
	err = m.Page(in.Page, in.Size).OrderDesc(dao.Role.Columns().Id).Scan(&out.List)
	if err != nil {
		return nil, err
	}
	if len(out.List) == 0 {
		return nil, nil
	}
	return out, nil
}

// GetListByXmSelect 获取XmSelect角色信息
func (s *sRole) GetListByXmSelect(ctx context.Context, UserId uint) (out []*model.BaseXmSelectItem, err error) {
	var roles []entity.Role
	err = dao.Role.Ctx(ctx).OrderDesc(dao.Role.Columns().Id).Scan(&roles)
	if err != nil {
		return
	}
	var selectedRoleIds []string
	if UserId > 0 {
		var userRoles []entity.UserRole
		err = dao.UserRole.Ctx(ctx).Where(dao.UserRole.Columns().UserId, UserId).OrderDesc(dao.UserRole.Columns().Id).Scan(&userRoles)
		if err != nil {
			return
		}
		for _, item := range userRoles {
			selectedRoleIds = append(selectedRoleIds, gconv.String(item.RoleId))
		}
	}
	for _, item := range roles {
		out = append(out, &model.BaseXmSelectItem{
			Name:     item.Name,
			Value:    gconv.String(item.Id),
			Selected: utils.IsContainStr(selectedRoleIds, gconv.String(item.Id)),
		})
	}
	return
}

// 获取角色详情
func (s *sRole) GetDetail(ctx context.Context, in model.RoleGetDetailInput) (out *model.RoleGetDetailOutput, err error) {
	out = &model.RoleGetDetailOutput{}
	err = dao.Role.Ctx(ctx).Where(dao.Role.Columns().Id, in.Id).Scan(&out)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// Create 创建角色
func (s *sRole) Create(ctx context.Context, in model.RoleCreateInput) (out model.RoleCreateOutput, err error) {
	lastInsertID, err := dao.Role.Ctx(ctx).Data(in).InsertAndGetId()
	if err != nil {
		return out, err
	}
	return model.RoleCreateOutput{RoleId: uint(lastInsertID)}, err
}

// Update 修改
func (s *sRole) Update(ctx context.Context, in model.RoleUpdateInput) error {
	_, err := dao.Role.Ctx(ctx).Data(in).FieldsEx(dao.Role.Columns().Id).Where(dao.Role.Columns().Id, in.Id).Update()
	if err != nil {
		return err
	}
	return nil
}

//Auth 授权角色
func (s *sRole) Auth(ctx context.Context, in model.RoleAuthInput) error {
	tx, err := dao.UserAdmin.DB().Begin(ctx)
	if err != nil {
		return err
	}
	// 方法退出时检验返回值，
	// 如果结果成功则执行tx.Commit()提交,
	// 否则执行tx.Rollback()回滚操作。
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var role *entity.Role
	err = dao.Role.Ctx(ctx).Where(dao.Role.Columns().Id, in.Id).Scan(&role)
	if err != nil {
		return err
	}
	_, err = dao.RoleMenu.Ctx(ctx).Where(dao.RoleMenu.Columns().RoleId, in.Id).Delete()
	if err != nil {
		return err
	}
	e := service.Casbin().CasBin(ctx)
	_, err = e.DeletePermissionsForUser(role.Name)
	if err != nil {
		return err
	}
	if len(in.AuthId) > 0 {
		var menuData []*entity.Menu
		err := dao.Menu.Ctx(ctx).WhereIn(dao.Menu.Columns().Id, in.AuthId).Scan(&menuData)
		if err != nil {
			return err
		}
		var gimp g.List
		for _, item := range menuData {
			gimp = append(gimp, g.Map{
				dao.RoleMenu.Columns().MenuId: item.Id,
				dao.RoleMenu.Columns().RoleId: in.Id,
			})
			if item.Path != "" && item.Method != "" {
				_, err2 := e.AddPermissionForUser(role.Name, item.Path, item.Method)
				if err2 != nil {
					return err2
				}
			}
		}
		_, err = dao.RoleMenu.Ctx(ctx).Data(gimp).Insert()
		if err != nil {
			return err
		}
	}
	return nil
}

// Delete 删除
func (s *sRole) Delete(ctx context.Context, in model.RoleGetDetailInput) error {
	var role *entity.Role
	err := dao.Role.Ctx(ctx).Where(dao.Role.Columns().Id, in.Id).Scan(&role)
	if err != nil {
		return err
	}
	_, err = dao.Role.Ctx(ctx).Where(dao.Role.Columns().Id, role.Id).Unscoped().Delete()
	if err != nil {
		return err
	}
	e := service.Casbin().CasBin(ctx)
	_, err = e.DeleteRole(role.Name)
	if err != nil {
		return err
	}
	return nil
}
